home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Utilities Experience
/
The Utilities Experience - Volume 1.iso
/
software
/
emulation
/
frodo
/
src
/
sam.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-02-10
|
46KB
|
1,978 lines
/*
* SAM.c - Simple Assembler and Monitor With Integrated System Explorer
*
* Copyright (C) 1994-1996 by Christian Bauer
*/
#include <exec/types.h>
#include <clib/dos_protos.h>
#include <clib/utility_protos.h>
#include "SAM.h"
#include "6526.h"
#include "6581.h"
#include "6569.h"
// Aus 6510.asm
extern UBYTE RA, RX, RY, RP, RPR, RDDR;
extern UWORD RPC, RS;
extern UBYTE SAMReadByte(UWORD address);
extern void SAMWriteByte(UWORD address, UBYTE byte);
extern UBYTE SAMMemConfig;
// Prototypes
void error(char *s); // Scanner
BOOL aborted(void);
void read_line(void);
char get_char(void);
void put_back(char c);
enum Token get_token(void);
enum RegToken get_reg_token(void);
UWORD get_number(void);
enum Token get_string(char *str);
BOOL expression(UWORD *number); // Parser
BOOL term(UWORD *number);
BOOL factor(UWORD *number);
BOOL address_args(void);
BOOL range_args(int def_range);
BOOL instr_args(UWORD *number, char *mode);
void help(void); // Routinen für die Befehle
void registers(void);
void display_registers(void);
void memory_dump(void);
void ascii_dump(void);
char conv_from_64(char c);
void screen_dump(void);
char conv_from_scode(char c);
void binary_dump(void);
void sprite_dump(void);
void byte_to_bin(UBYTE byte, char *str);
void disassemble(void);
int disass_line(UWORD adr, UBYTE op, UBYTE lo, UBYTE hi);
void assemble(void);
char find_mnemonic(char op1, char op2, char op3);
BOOL find_opcode(char mnem, char mode, UBYTE *opcode);
void mem_config(void);
void fill(void);
void compare(void);
void transfer(void);
void modify(void);
void print_expr(void);
void redir_output(void);
void int_vectors(void);
void view_state(void);
void view_cia_state(void);
void dump_cia_ints(UBYTE int);
void view_sid_state(void);
void dump_sid_waveform(UBYTE wave);
void view_vic_state(void);
void dump_spr_flags(UBYTE f);
void dump_vic_ints(UBYTE int);
void load_data(void);
void save_data(void);
// FileHandles für Eingabe, Ausgabe und Fehler
BPTR fin, fout, ferr;
// Eingabezeile
#define INPUT_LENGTH 80
char input[INPUT_LENGTH];
char *in_ptr;
UWORD address, end_address;
// Eingabetoken
enum Token {
T_NULL, // Ungültiges Token
T_END, // Ende der Zeile
T_NUMBER, // Hexadezimalzahl
T_STRING, // In "" eingeschlossener String
T_LPAREN, // '('
T_RPAREN, // ')'
T_ADD, // '+'
T_SUB, // '-'
T_MUL, // '*'
T_DIV, // '/'
T_COMMA, // ','
T_IMMED, // '#'
T_X, // 'x'
T_Y, // 'y'
T_PC, // 'pc'
T_SP // 'sp'
};
// Registernamen
enum RegToken {
RT_NULL, // Ungültiges Token
RT_END, // Ende der Zeile
RT_A, // 'a'
RT_X, // 'x'
RT_Y, // 'y'
RT_PC, // 'pc'
RT_SP, // 'sp'
RT_DR, // 'dr'
RT_PR // 'pr'
};
enum Token the_token; // Auch RegToken für get_reg_token
UWORD the_number; // Enthält die Zahl, wenn the_token==T_NUMBER
char the_string[INPUT_LENGTH]; // Enthält den String, wenn the_token==T_STRING
// Adressierungsarten
enum {
A_IMPL,
A_ACCU, // A
A_IMM, // #zz
A_REL, // Branches
A_ZERO, // zz
A_ZEROX, // zz,x
A_ZEROY, // zz,y
A_ABS, // zzzz
A_ABSX, // zzzz,x
A_ABSY, // zzzz,y
A_IND, // (zzzz)
A_INDX, // (zz,x)
A_INDY // (zz),y
};
// Mnemonics
enum {
M_ADC, M_AND, M_ASL, M_BCC, M_BCS, M_BEQ, M_BIT, M_BMI, M_BNE, M_BPL,
M_BRK, M_BVC, M_BVS, M_CLC, M_CLD, M_CLI, M_CLV, M_CMP, M_CPX, M_CPY,
M_DEC, M_DEX, M_DEY, M_EOR, M_INC, M_INX, M_INY, M_JMP, M_JSR, M_LDA,
M_LDX, M_LDY, M_LSR, M_NOP, M_ORA, M_PHA, M_PHP, M_PLA, M_PLP, M_ROL,
M_ROR, M_RTI, M_RTS, M_SBC, M_SEC, M_SED, M_SEI, M_STA, M_STX, M_STY,
M_TAX, M_TAY, M_TSX, M_TXA, M_TXS, M_TYA,
M_ILLEGAL, // Ab hier kommen die undokumentierten Opcodes
M_IANC, M_IANE, M_IARR, M_IASR, M_IDCP, M_IISB, M_IJAM, M_INOP, M_ILAS,
M_ILAX, M_ILXA, M_IRLA, M_IRRA, M_ISAX, M_ISBC, M_ISBX, M_ISHA, M_ISHS,
M_ISHX, M_ISHY, M_ISLO, M_ISRE,
M_MAXIMUM // Höchstes Element
};
// Zu jedem Opcode das Mnemonic
const char mnemonic[256] = {
M_BRK , M_ORA , M_IJAM, M_ISLO, M_INOP, M_ORA, M_ASL , M_ISLO, // 00
M_PHP , M_ORA , M_ASL , M_IANC, M_INOP, M_ORA, M_ASL , M_ISLO,
M_BPL , M_ORA , M_IJAM, M_ISLO, M_INOP, M_ORA, M_ASL , M_ISLO, // 10
M_CLC , M_ORA , M_INOP, M_ISLO, M_INOP, M_ORA, M_ASL , M_ISLO,
M_JSR , M_AND , M_IJAM, M_IRLA, M_BIT , M_AND, M_ROL , M_IRLA, // 20
M_PLP , M_AND , M_ROL , M_IANC, M_BIT , M_AND, M_ROL , M_IRLA,
M_BMI , M_AND , M_IJAM, M_IRLA, M_INOP, M_AND, M_ROL , M_IRLA, // 30
M_SEC , M_AND , M_INOP, M_IRLA, M_INOP, M_AND, M_ROL , M_IRLA,
M_RTI , M_EOR , M_IJAM, M_ISRE, M_INOP, M_EOR, M_LSR , M_ISRE, // 40
M_PHA , M_EOR , M_LSR , M_IASR, M_JMP , M_EOR, M_LSR , M_ISRE,
M_BVC , M_EOR , M_IJAM, M_ISRE, M_INOP, M_EOR, M_LSR , M_ISRE, // 50
M_CLI , M_EOR , M_INOP, M_ISRE, M_INOP, M_EOR, M_LSR , M_ISRE,
M_RTS , M_ADC , M_IJAM, M_IRRA, M_INOP, M_ADC, M_ROR , M_IRRA, // 60
M_PLA , M_ADC , M_ROR , M_IARR, M_JMP , M_ADC, M_ROR , M_IRRA,
M_BVS , M_ADC , M_IJAM, M_IRRA, M_INOP, M_ADC, M_ROR , M_IRRA, // 70
M_SEI , M_ADC , M_INOP, M_IRRA, M_INOP, M_ADC, M_ROR , M_IRRA,
M_INOP, M_STA , M_INOP, M_ISAX, M_STY , M_STA, M_STX , M_ISAX, // 80
M_DEY , M_INOP, M_TXA , M_IANE, M_STY , M_STA, M_STX , M_ISAX,
M_BCC , M_STA , M_IJAM, M_ISHA, M_STY , M_STA, M_STX , M_ISAX, // 90
M_TYA , M_STA , M_TXS , M_ISHS, M_ISHY, M_STA, M_ISHX, M_ISHA,
M_LDY , M_LDA , M_LDX , M_ILAX, M_LDY , M_LDA, M_LDX , M_ILAX, // a0
M_TAY , M_LDA , M_TAX , M_ILXA, M_LDY , M_LDA, M_LDX , M_ILAX,
M_BCS , M_LDA , M_IJAM, M_ILAX, M_LDY , M_LDA, M_LDX , M_ILAX, // b0
M_CLV , M_LDA , M_TSX , M_ILAS, M_LDY , M_LDA, M_LDX , M_ILAX,
M_CPY , M_CMP , M_INOP, M_IDCP, M_CPY , M_CMP, M_DEC , M_IDCP, // c0
M_INY , M_CMP , M_DEX , M_ISBX, M_CPY , M_CMP, M_DEC , M_IDCP,
M_BNE , M_CMP , M_IJAM, M_IDCP, M_INOP, M_CMP, M_DEC , M_IDCP, // d0
M_CLD , M_CMP , M_INOP, M_IDCP, M_INOP, M_CMP, M_DEC , M_IDCP,
M_CPX , M_SBC , M_INOP, M_IISB, M_CPX , M_SBC, M_INC , M_IISB, // e0
M_INX , M_SBC , M_NOP , M_ISBC, M_CPX , M_SBC, M_INC , M_IISB,
M_BEQ , M_SBC , M_IJAM, M_IISB, M_INOP, M_SBC, M_INC , M_IISB, // f0
M_SED , M_SBC , M_INOP, M_IISB, M_INOP, M_SBC, M_INC , M_IISB
};
// Zu jedem Opcode die Adressierungsart
const char adr_mode[256] = {
A_IMPL, A_INDX, A_IMPL, A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // 00
A_IMPL, A_IMM , A_ACCU, A_IMM , A_ABS , A_ABS , A_ABS , A_ABS,
A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX, // 10
A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX,
A_ABS , A_INDX, A_IMPL, A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // 20
A_IMPL, A_IMM , A_ACCU, A_IMM , A_ABS , A_ABS , A_ABS , A_ABS,
A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX, // 30
A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX,
A_IMPL, A_INDX, A_IMPL, A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // 40
A_IMPL, A_IMM , A_ACCU, A_IMM , A_ABS , A_ABS , A_ABS , A_ABS,
A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX, // 50
A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX,
A_IMPL, A_INDX, A_IMPL, A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // 60
A_IMPL, A_IMM , A_ACCU, A_IMM , A_IND , A_ABS , A_ABS , A_ABS,
A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX, // 70
A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX,
A_IMM , A_INDX, A_IMM , A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // 80
A_IMPL, A_IMM , A_IMPL, A_IMM , A_ABS , A_ABS , A_ABS , A_ABS,
A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROY, A_ZEROY, // 90
A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSY , A_ABSY,
A_IMM , A_INDX, A_IMM , A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // a0
A_IMPL, A_IMM , A_IMPL, A_IMM , A_ABS , A_ABS , A_ABS , A_ABS,
A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROY, A_ZEROY, // b0
A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSY , A_ABSY,
A_IMM , A_INDX, A_IMM , A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // c0
A_IMPL, A_IMM , A_IMPL, A_IMM , A_ABS , A_ABS , A_ABS , A_ABS,
A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX, // d0
A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX,
A_IMM , A_INDX, A_IMM , A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // e0
A_IMPL, A_IMM , A_IMPL, A_IMM , A_ABS , A_ABS , A_ABS , A_ABS,
A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX, // f0
A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX
};
// Zu jedem Mnemonic die Zeichen
const char mnem_1[] = "aaabbbbbbbbbbcccccccdddeiiijjllllnopppprrrrssssssstttttt?aaaadijnlllrrsssssssss";
const char mnem_2[] = "dnscceimnprvvllllmppeeeonnnmsdddsorhhlloottbeeetttaasxxy?nnrscsaoaaxlrabbhhhhlr";
const char mnem_3[] = "cdlcsqtielkcscdivpxycxyrcxypraxyrpaapaplrisccdiaxyxyxasa?cerrpbmpsxaaaxcxasxyoe";
// Zu jeder Adressierungsart die Befehlslänge
const char adr_length[] = {1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2};
/*
* SAM öffnen und handhaben
*/
void SAM(void)
{
BOOL done = FALSE;
char c;
if (fin = fout = ferr = Open("CON:0/0/640/480/SAM", MODE_NEWFILE)) {
FPuts(ferr, "\n *** SAM - Simple Assembler and Monitor ***\n *** Press 'h' for help ***\n\n");
display_registers();
address = RPC;
while (!done) {
Write(ferr, "> ", 2);
read_line();
while ((c = get_char()) == ' ') ;
switch (c) {
case 'a': // Assemblieren
get_token();
assemble();
break;
case 'b': // Binär-Dump
get_token();
binary_dump();
break;
case 'c': // Vergleichen
get_token();
compare();
break;
case 'd': // Disassemblieren
get_token();
disassemble();
break;
case 'e': // Interrupt-Vektoren
int_vectors();
break;
case 'f': // Füllen
get_token();
fill();
break;
case 'h': // Help
help();
break;
case 'i': // ASCII-Dump
get_token();
ascii_dump();
break;
case 'k': // Speicherkonfiguration
get_token();
mem_config();
break;
case 'l': // Daten laden
get_token();
load_data();
break;
case 'm': // Memory-Dump
get_token();
memory_dump();
break;
case 'n': // Screen-Code-Dump
get_token();
screen_dump();
break;
case 'o': // Ausgabe umleiten
get_token();
redir_output();
break;
case 'p': // Sprite-Dump
get_token();
sprite_dump();
break;
case 'r': // Register
get_reg_token();
registers();
break;
case 's': // Daten speichern
get_token();
save_data();
break;
case 't': // Transfer
get_token();
transfer();
break;
case 'v': // View machine state
view_state();
break;
case 'x': // Exit
done = TRUE;
break;
case ':': // Ändern
get_token();
modify();
break;
case '?': // Ausdruck berechnen
get_token();
print_expr();
break;
case '\n': // Leerzeile
break;
default: // Unbekannter Befehl
error("Unknown command");
break;
}
}
Close(fin);
if (fout != ferr)
Close(fout);
}
}
/*
* Fehlermeldung ausgeben
*/
void error(char *s)
{
FPrintf(ferr, "*** %s\n", s);
}
/*
* CTRL-C gedrückt?
*/
#include <dos/dos.h>
#include <clib/exec_protos.h>
BOOL aborted(void)
{
return SetSignal(0, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C;
}
/*
* Eine Zeile von der Tastatur lesen
*/
void read_line(void)
{
FGets(fin, in_ptr = input, INPUT_LENGTH);
}
/*
* Ein Zeichen aus der Eingabezeile lesen
*/
char get_char(void)
{
return *in_ptr++;
}
/*
* Zeichen in die Eingabezeile zurückpacken
*/
void put_back(char c)
{
*(--in_ptr) = c;
}
/*
* Scanner: Ein Token aus der Eingabezeile lesen
*/
enum Token get_token(void)
{
char c;
// Leerzeichen überspringen
while ((c = get_char()) == ' ') ;
switch (ToLower(c)) {
case '\n':
return the_token = T_END;
case '(':
return the_token = T_LPAREN;
case ')':
return the_token = T_RPAREN;
case '+':
return the_token = T_ADD;
case '-':
return the_token = T_SUB;
case '*':
return the_token = T_MUL;
case '/':
return the_token = T_DIV;
case ',':
return the_token = T_COMMA;
case '#':
return the_token = T_IMMED;
case 'x':
return the_token = T_X;
case 'y':
return the_token = T_Y;
case 'p':
if (ToLower(get_char()) == 'c')
return the_token = T_PC;
else {
error("Unrecognized token");
return the_token = T_NULL;
}
case 's':
if (ToLower(get_char()) == 'p')
return the_token = T_SP;
else {
error("Unrecognized token");
return the_token = T_NULL;
}
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
put_back(c);
the_number = get_number();
return the_token = T_NUMBER;
case '"':
return the_token = get_string(the_string);
default:
error("Unrecognized token");
return the_token = T_NULL;
}
}
enum RegToken get_reg_token(void)
{
char c;
// Leerzeichen überspringen
while ((c = get_char()) == ' ') ;
switch (ToLower(c)) {
case '\n':
return the_token = RT_END;
case 'a':
return the_token = RT_A;
case 'd':
if (ToLower(get_char()) == 'r')
return the_token = RT_DR;
else {
error("Unrecognized token");
return the_token = RT_NULL;
}
case 'p':
if ((c = ToLower(get_char())) == 'c')
return the_token = RT_PC;
else if (c == 'r')
return the_token = RT_PR;
else {
error("Unrecognized token");
return the_token = RT_NULL;
}
case 's':
if (ToLower(get_char()) == 'p')
return the_token = RT_SP;
else {
error("Unrecognized token");
return the_token = RT_NULL;
}
case 'x':
return the_token = RT_X;
case 'y':
return the_token = RT_Y;
default:
error("Unrecognized token");
return the_token = RT_NULL;
}
}
UWORD get_number(void)
{
char c;
UWORD i = 0;
while (((c = ToLower(get_char())) >= '0') && (c <= '9') || (c >= 'a') && (c <= 'f'))
if (c < 'a')
i = (i << 4) + (c - '0');
else
i = (i << 4) + (c - 'a' + 10);
put_back(c);
return i;
}
enum Token get_string(char *str)
{
char c;
while ((c = get_char()) != '\n') {
if (c == '"') {
*str = 0;
return T_STRING;
}
*str++ = c;
}
error("Unterminated string");
return T_NULL;
}
/*
* expression = term {(ADD | SUB) term}
* TRUE: OK, FALSE: Fehler
*/
BOOL expression(UWORD *number)
{
UWORD accu, trm;
if (!term(&accu))
return FALSE;
for (;;)
switch (the_token) {
case T_ADD:
get_token();
if (!term(&trm))
return FALSE;
accu += trm;
break;
case T_SUB:
get_token();
if (!term(&trm))
return FALSE;
accu -= trm;
break;
default:
*number = accu;
return TRUE;
}
}
/*
* term = factor {(MUL | DIV) factor}
* TRUE: OK, FALSE: Fehler
*/
BOOL term(UWORD *number)
{
UWORD accu, fact;
if (!factor(&accu))
return FALSE;
for (;;)
switch (the_token) {
case T_MUL:
get_token();
if (!factor(&fact))
return FALSE;
accu *= fact;
break;
case T_DIV:
get_token();
if (!factor(&fact))
return FALSE;
if (fact == 0) {
error("Division by 0");
return FALSE;
}
accu /= fact;
break;
default:
*number = accu;
return TRUE;
}
}
/*
* factor = NUMBER | PC | SP | LPAREN expression RPAREN
* TRUE: OK, FALSE: Fehler
*/
BOOL factor(UWORD *number)
{
switch (the_token) {
case T_NUMBER:
*number = the_number;
get_token();
return TRUE;
case T_PC:
get_token();
*number = RPC;
return TRUE;
case T_SP:
get_token();
*number = RS;
return TRUE;
case T_LPAREN:
get_token();
if (expression(number))
if (the_token == T_RPAREN) {
get_token();
return TRUE;
} else {
error("Missing ')'");
return FALSE;
}
else {
error("Error in expression");
return FALSE;
}
case T_END:
error("Required argument missing");
return FALSE;
default:
error("'pc', 'sp', '(' or number expected");
return FALSE;
}
}
/*
* address_args = [expression] END
*
* Startadresse nach address lesen
*
* TRUE: OK, FALSE: Fehler
*/
BOOL address_args(void)
{
if (the_token == T_END)
return TRUE;
else {
if (!expression(&address))
return FALSE;
return the_token == T_END;
}
}
/*
* range_args = [expression] [[COMMA] expression] END
*
* Startadresse nach address, Endadresse nach end_address lesen
*
* TRUE: OK, FALSE: Fehler
*/
BOOL range_args(int def_range)
{
end_address = address + def_range;
if (the_token == T_END)
return TRUE;
else {
if (!expression(&address))
return FALSE;
end_address = address + def_range;
if (the_token == T_END)
return TRUE;
else {
if (the_token == T_COMMA) get_token();
if (!expression(&end_address))
return FALSE;
return the_token == T_END;
}
}
}
/*
* instr_args = END
* | IMMED NUMBER END
* | NUMBER [COMMA (X | Y)] END
* | LPAREN NUMBER (RPAREN [COMMA Y] | COMMA X RPAREN) END
*
* Argumente eines 6510-Befehls lesen, Adresse und Adressierungsart ermitteln
*
* TRUE: OK, FALSE: Fehler
*/
BOOL instr_args(UWORD *number, char *mode)
{
switch (the_token) {
case T_END:
*mode = A_IMPL;
return TRUE;
case T_IMMED:
get_token();
if (the_token == T_NUMBER) {
*number = the_number;
*mode = A_IMM;
get_token();
return the_token == T_END;
} else {
error("Number expected");
return FALSE;
}
case T_NUMBER:
*number = the_number;
get_token();
switch (the_token) {
case T_END:
if (*number < 0x100)
*mode = A_ZERO;
else
*mode = A_ABS;
return TRUE;
case T_COMMA:
get_token();
switch (the_token) {
case T_X:
get_token();
if (*number < 0x100)
*mode = A_ZEROX;
else
*mode = A_ABSX;
return the_token == T_END;
case T_Y:
get_token();
if (*number < 0x100)
*mode = A_ZEROY;
else
*mode = A_ABSY;
return the_token == T_END;
default:
error("Illegal index register");
return FALSE;
}
default:
return FALSE;
}
case T_LPAREN:
get_token();
if (the_token == T_NUMBER) {
*number = the_number;
get_token();
switch (the_token) {
case T_RPAREN:
get_token();
switch (the_token) {
case T_END:
*mode = A_IND;
return TRUE;
case T_COMMA:
get_token();
if (the_token == T_Y) {
*mode = A_INDY;
get_token();
return the_token == T_END;
} else {
error("Only 'y' index register allowed");
return FALSE;
}
default:
error("Illegal characters after ')'");
return FALSE;
}
case T_COMMA:
get_token();
if (the_token == T_X) {
get_token();
if (the_token == T_RPAREN) {
*mode = A_INDX;
get_token();
return the_token == T_END;
} else {
error("')' expected");
return FALSE;
}
} else {
error("Only 'x' index register allowed");
return FALSE;
}
default:
error("')' or ',' expected");
return FALSE;
}
} else {
error("Number expected");
return FALSE;
}
default:
error("'(', '#' or number expected");
return FALSE;
}
}
/*
* Hilfstext anzeigen
* ?
*/
void help(void)
{
FPuts(fout, "a [start] Assemble\n"
"b [start] [end] Binary dump\n"
"c start end dest Compare memory\n"
"d [start] [end] Disassemble\n"
"e Show interrupt vectors\n"
"f start end byte Fill memory\n"
"i [start] [end] ASCII/PETSCII dump\n"
"k [config] Show/set memory configuration\n"
"l start \"file\" Load data\n"
"m [start] [end] Memory dump\n"
"n [start] [end] Screen code dump\n"
"o [\"file\"] Redirect output\n"
"p [start] [end] Sprite dump\n"
"r [reg value] Show/set registers\n"
"s start end \"file\" Save data\n"
"t start end dest Transfer memory\n"
"vc1 View CIA 1 state\n"
"vc2 View CIA 2 state\n"
"vs View SID state\n"
"vv View VIC state\n"
"x Return to Frodo\n"
": addr {byte} Modify memory\n"
"? expression Calculate expression\n");
}
/*
* 6510-Register anzeigen/ändern
* r [reg value]
*/
void registers(void)
{
enum RegToken the_reg;
UWORD value;
if (the_token != RT_END)
switch (the_reg = the_token) {
case RT_A:
case RT_X:
case RT_Y:
case RT_PC:
case RT_SP:
case RT_DR:
case RT_PR:
get_token();
if (!expression(&value))
return;
switch (the_reg) {
case RT_A:
RA = value;
break;
case RT_X:
RX = value;
break;
case RT_Y:
RY = value;
break;
case RT_PC:
RPC = value;
break;
case RT_SP:
RS = (value & 0xff) | 0x0100;
break;
case RT_DR:
RDDR = value;
break;
case RT_PR:
RPR = value;
break;
}
break;
default:
return;
}
display_registers();
}
void display_registers(void)
{
FPuts(fout, " PC A X Y SP DR PR NVDIZC Instruction\n");
FPrintf(fout, "%04lx %02lx %02lx %02lx %04lx %02lx %02lx %lc%lc%lc%lc%lc%lc ",
RPC, RA, RX, RY, RS, RDDR, RPR,
RP & 0x80 ? '1' : '0', RP & 0x40 ? '1' : '0', RP & 0x08 ? '1' : '0',
RP & 0x04 ? '1' : '0', RP & 0x02 ? '1' : '0', RP & 0x01 ? '1' : '0');
disass_line(RPC, SAMReadByte(RPC), SAMReadByte(RPC+1), SAMReadByte(RPC+2));
}
/*
* Memory-Dump
* m [start] [end]
*/
#define MEMDUMP_BPL 16 // Bytes pro Zeile
void memory_dump(void)
{
BOOL done = FALSE;
short i;
UBYTE mem[MEMDUMP_BPL + 2];
UBYTE byte;
mem[MEMDUMP_BPL] = 0;
if (!range_args(16 * MEMDUMP_BPL - 1)) // 16 Zeilen, wenn keine Endadresse angegeben
return;
do {
FPrintf(fout, "%04lx:", address);
for (i=0; i<MEMDUMP_BPL; i++, address++) {
if (address == end_address) done = TRUE;
FPrintf(fout, " %02lx", byte = SAMReadByte(address));
if ((byte >= ' ') && (byte <= '~'))
mem[i] = conv_from_64(byte);
else
mem[i] = '.';
}
FPrintf(fout, " '%s'\n", mem);
} while (!done && !aborted());
}
/*
* ASCII-Dump
* i [start] [end]
*/
#define ASCIIDUMP_BPL 64 // Bytes pro Zeile
void ascii_dump(void)
{
BOOL done = FALSE;
short i;
UBYTE mem[ASCIIDUMP_BPL + 2];
UBYTE byte;
mem[ASCIIDUMP_BPL] = 0;
if (!range_args(16 * ASCIIDUMP_BPL - 1)) // 16 Zeilen, wenn keine Endadresse angegeben
return;
do {
FPrintf(fout, "%04lx:", address);
for (i=0; i<ASCIIDUMP_BPL; i++, address++) {
if (address == end_address) done = TRUE;
byte = SAMReadByte(address);
if ((byte >= ' ') && (byte <= '~'))
mem[i] = conv_from_64(byte);
else
mem[i] = '.';
}
FPrintf(fout, " '%s'\n", mem);
} while (!done && !aborted());
}
/*
* Umwandlung PETSCII->ASCII
*/
char conv_from_64(char c)
{
if ((c >= 'A') && (c <= 'Z') || (c >= 'a') && (c <= 'z'))
return c ^ 0x20;
else
return c;
}
/*
* Screen-Code-Dump
* n [start] [end]
*/
#define SCRDUMP_BPL 64 // Bytes pro Zeile
void screen_dump(void)
{
BOOL done = FALSE;
short i;
UBYTE mem[SCRDUMP_BPL + 2];
UBYTE byte;
mem[SCRDUMP_BPL] = 0;
if (!range_args(16 * SCRDUMP_BPL - 1)) // 16 Zeilen, wenn keine Endadresse angegeben
return;
do {
FPrintf(fout, "%04lx:", address);
for (i=0; i<SCRDUMP_BPL; i++, address++) {
if (address == end_address) done = TRUE;
byte = SAMReadByte(address);
if (byte < 90)
mem[i] = conv_from_scode(byte);
else
mem[i] = '.';
}
FPrintf(fout, " '%s'\n", mem);
} while (!done && !aborted());
}
/*
* Umwandlung Bildschirmcode->ASCII
*/
char conv_from_scode(char c)
{
c &= 0x7f;
if (c <= 31)
return c + 64;
else
if (c >= 64)
return c + 32;
else
return c;
}
/*
* Binär-Dump
* b [start] [end]
*/
void binary_dump(void)
{
BOOL done = FALSE;
char bin[10];
bin[8] = 0;
if (!range_args(7)) // 8 Zeilen, wenn keine Endadresse angegeben
return;
do {
if (address == end_address) done = TRUE;
byte_to_bin(SAMReadByte(address), bin);
FPrintf(fout, "%04lx: %s\n", address++, bin);
} while (!done && !aborted());
}
/*
* Sprite-Daten-Dump
* p [start] [end]
*/
void sprite_dump(void)
{
BOOL done = FALSE;
short i;
char bin[10];
bin[8] = 0;
if (!range_args(21 * 3 - 1)) // 21 Zeilen, wenn keine Endadresse angegeben
return;
do {
FPrintf(fout, "%04lx: ", address);
for (i=0; i<3; i++, address++) {
if (address == end_address) done = TRUE;
byte_to_bin(SAMReadByte(address), bin);
FPrintf(fout, "%s", bin);
}
FPutC(fout, '\n');
} while (!done && !aborted());
}
/*
* Ein Byte in Binärfolge umwandeln
*/
void byte_to_bin(UBYTE byte, char *str)
{
short i;
for (i=0; i<8; i++, byte<<=1)
if (byte & 0x80)
str[i] = '#';
else
str[i] = '.';
}
/*
* Disassemblieren
* d [start] [end]
*/
void disassemble(void)
{
BOOL done = FALSE;
short i;
UBYTE op[3];
UWORD adr;
if (!range_args(31)) // 32 Bytes, wenn keine Endadresse angegeben
return;
do {
FPrintf(fout, "%04lx:", adr = address);
for (i=0; i<3; i++, adr++) {
if (adr == end_address) done = TRUE;
op[i] = SAMReadByte(adr);
}
address += disass_line(address, op[0], op[1], op[2]);
} while (!done && !aborted());
}
/*
* Einen Befehl disassemblieren, Länge zurückgeben
*/
int disass_line(UWORD adr, UBYTE op, UBYTE lo, UBYTE hi)
{
char mode = adr_mode[op], mnem = mnemonic[op];
// Befehlsbytes hexadezimal ausgeben
switch (adr_length[mode]) {
case 1:
FPrintf(fout, " %02lx ", op);
break;
case 2:
FPrintf(fout, " %02lx %02lx ", op, lo);
break;
case 3:
FPrintf(fout, " %02lx %02lx %02lx ", op, lo, hi);
break;
}
// Undokumentierte Opcodes mit Stern markieren
if (mnem > M_ILLEGAL)
FPutC(fout, '*');
else
FPutC(fout, ' ');
// Mnemonic ausgeben
FPrintf(fout, "%lc%lc%lc ", mnem_1[mnem], mnem_2[mnem], mnem_3[mnem]);
// Argument ausgeben
switch (mode) {
case A_IMPL:
break;
case A_ACCU:
FPuts(fout, "a");
break;
case A_IMM:
FPrintf(fout, "#%02lx", lo);
break;
case A_REL:
FPrintf(fout, "%04lx", ((adr + 2) + (BYTE)lo) & 0xffff);
break;
case A_ZERO:
FPrintf(fout, "%02lx", lo);
break;
case A_ZEROX:
FPrintf(fout, "%02lx,x", lo);
break;
case A_ZEROY:
FPrintf(fout, "%02lx,y", lo);
break;
case A_ABS:
FPrintf(fout, "%04lx", (hi << 8) | lo);
break;
case A_ABSX:
FPrintf(fout, "%04lx,x", (hi << 8) | lo);
break;
case A_ABSY:
FPrintf(fout, "%04lx,y", (hi << 8) | lo);
break;
case A_IND:
FPrintf(fout, "(%04lx)", (hi << 8) | lo);
break;
case A_INDX:
FPrintf(fout, "(%02lx,x)", lo);
break;
case A_INDY:
FPrintf(fout, "(%02lx),y", lo);
break;
}
FPutC(fout, '\n');
return adr_length[mode];
}
/*
* Assemblieren
* a [start]
*/
void assemble(void)
{
BOOL done = FALSE;
char c1, c2, c3;
char mnem, mode;
UBYTE opcode;
UWORD arg;
WORD rel;
// Parameter lesen
if (!address_args())
return;
do {
FPrintf(fout, "%04lx> ", address);
read_line();
c1 = ToLower(get_char());
c2 = ToLower(get_char());
c3 = ToLower(get_char());
if (c1 != '\n') {
if ((mnem = find_mnemonic(c1, c2, c3)) != M_ILLEGAL) {
get_token();
if (instr_args(&arg, &mode)) {
// Ggf. A_IMPL -> A_ACCU
if ((mode == A_IMPL) && find_opcode(mnem, A_ACCU, &opcode))
mode = A_ACCU;
// Relative Adressierung getrennt behandeln
if (((mode == A_ABS) || (mode == A_ZERO)) && find_opcode(mnem, A_REL, &opcode)) {
mode = A_REL;
rel = arg - (address + 2) & 0xffff;
if ((rel < -128) || (rel > 127)) {
error("Branch too long");
continue;
} else
arg = rel & 0xff;
}
if (find_opcode(mnem, mode, &opcode)) {
// Disassemblierte Zeile ausgeben
FPrintf(fout, "\v%04lx:", address);
disass_line(address, opcode, arg & 0xff, arg >> 8);
switch (adr_length[mode]) {
case 1:
SAMWriteByte(address++, opcode);
break;
case 2:
SAMWriteByte(address++, opcode);
SAMWriteByte(address++, arg);
break;
case 3:
SAMWriteByte(address++, opcode);
SAMWriteByte(address++, arg & 0xff);
SAMWriteByte(address++, arg >> 8);
break;
default:
error("Internal error");
break;
}
} else // Adressierungsart paßt nicht zum Befehl
error("Addressing mode not supported by instruction");
} else // Nicht erkannte Adressierungsart
error("Unrecognized addressing mode");
} else // Mnemonic nicht gefunden
error("Unknown instruction");
} else // Leerzeile beendet die Eingabe
done = TRUE;
} while (!done);
}
/*
* Zu drei Buchstaben den passenden Mnemonic-Code finden
* M_ILLEGAL: Kein passendes Mnemonic gefunden
*/
char find_mnemonic(char op1, char op2, char op3)
{
int i;
char c1, c2, c3;
for (i=0; i<M_MAXIMUM; i++)
if ((mnem_1[i] == op1) && (mnem_2[i] == op2) && (mnem_3[i] == op3))
return i;
return M_ILLEGAL;
}
/*
* Opcode eines Befehls ermitteln, Mnemonic und Adressierungsart gegeben
* TRUE: OK, FALSE: Mnemonic kommt mit dieser Adressierungsart nicht vor
*/
BOOL find_opcode(char mnem, char mode, UBYTE *opcode)
{
int i;
for (i=0; i<256; i++)
if ((mnemonic[i] == mnem) && (adr_mode[i] == mode)) {
*opcode = i;
return TRUE;
}
return FALSE;
}
/*
* Speicherkonfiguration anzeigen/setzen
* k [config]
*/
void mem_config(void)
{
UWORD con;
if (the_token != T_END)
if (!expression(&con))
return;
else
SAMMemConfig = con;
else
con = SAMMemConfig;
FPrintf(fout, "Configuration: %ld\n", con & 7);
FPrintf(fout, "A000-BFFF: %s\n", (con & 3) == 3 ? "Basic" : "RAM");
FPrintf(fout, "D000-DFFF: %s\n", (con & 3) ? ((con & 4) ? "I/O" : "Char") : "RAM");
FPrintf(fout, "E000-FFFF: %s\n", (con & 2) ? "Kernal" : "RAM");
}
/*
* Füllen
* k start end byte
*/
void fill(void)
{
BOOL done = FALSE;
UWORD adr, end_adr, value;
if (!expression(&adr))
return;
if (!expression(&end_adr))
return;
if (!expression(&value))
return;
do {
if (adr == end_adr) done = TRUE;
SAMWriteByte(adr++, value);
} while (!done);
}
/*
* Vergleichen
* c start end dest
*/
void compare(void)
{
BOOL done = FALSE;
UWORD adr, end_adr, dest;
int num = 0;
if (!expression(&adr))
return;
if (!expression(&end_adr))
return;
if (!expression(&dest))
return;
do {
if (adr == end_adr) done = TRUE;
if (SAMReadByte(adr) != SAMReadByte(dest)) {
FPrintf(fout, "%04lx ", adr);
num++;
if (!(num & 7))
FPutC(fout, '\n');
}
adr++; dest++;
} while (!done && !aborted());
if (num & 7)
FPutC(fout, '\n');
FPrintf(fout, "%ld byte(s) different\n", num);
}
/*
* Kopieren
* t start end dest
*/
void transfer(void)
{
BOOL done = FALSE;
UWORD adr, end_adr, dest;
if (!expression(&adr))
return;
if (!expression(&end_adr))
return;
if (!expression(&dest))
return;
if (dest < adr)
do {
if (adr == end_adr) done = TRUE;
SAMWriteByte(dest++,SAMReadByte(adr++));
} while (!done);
else {
dest += end_adr - adr;
do {
if (adr == end_adr) done = TRUE;
SAMWriteByte(dest--,SAMReadByte(end_adr--));
} while (!done);
}
}
/*
* Speicher ändern
* : addr {byte}
*/
void modify(void)
{
UWORD adr, val;
if (!expression(&adr))
return;
while (the_token != T_END)
if (expression(&val))
SAMWriteByte(adr++, val);
else
return;
}
/*
* Ausdruck berechnen und anzeigen
* ? expression
*/
void print_expr(void)
{
UWORD val;
if (!expression(&val))
return;
FPrintf(fout, "Hex: %04lx\nDec: %lu\n", val, val);
}
/*
* Ausgabe umleiten
* o ["file"]
*/
void redir_output(void)
{
// Alte Datei schließen
if (fout != ferr) {
Close(fout);
fout = ferr;
return;
}
// Kein Argument angegeben, dann weiter nichts tun
if (the_token == T_END)
return;
// Sonst Datei öffnen
if (the_token == T_STRING) {
if (!(fout = Open(the_string, MODE_NEWFILE)))
error("Unable to open file");
} else
error("'\"' around file name expected");
}
/*
* Interrupt-Vektoren anzeigen
*/
void int_vectors(void)
{
FPuts(fout, " IRQ BRK NMI\n");
FPrintf(fout, "6510 : %04lx %04lx %04lx\n",
SAMReadByte(0xffff) << 8 | SAMReadByte(0xfffe),
SAMReadByte(0xffff) << 8 | SAMReadByte(0xfffe),
SAMReadByte(0xfffb) << 8 | SAMReadByte(0xfffa));
if (SAMMemConfig & 2)
FPrintf(fout, "Kernal: %04lx %04lx %04lx\n",
SAMReadByte(0x0315) << 8 | SAMReadByte(0x0314),
SAMReadByte(0x0317) << 8 | SAMReadByte(0x0316),
SAMReadByte(0x0319) << 8 | SAMReadByte(0x0318));
}
/*
* Zustand der Customchips anzeigen
*/
void view_state(void)
{
switch (get_char()) {
case 'c': // CIA
view_cia_state();
break;
case 's': // SID
view_sid_state();
break;
case 'v': // VIC
view_vic_state();
break;
default:
error("Unknown command");
break;
}
}
void view_cia_state(void)
{
CIADump cd;
switch (get_char()) {
case '1':
GetCIA1Dump(&cd);
break;
case '2':
GetCIA2Dump(&cd);
break;
default:
error("Unknown command");
return;
}
FPrintf(fout, "Timer A : %s\n", cd.cra & 1 ? "On" : "Off");
FPrintf(fout, " Counter : %04lx Latch: %04lx\n", (cd.ta_hi << 8) | cd.ta_lo, (cd.ltcha_hi << 8) | cd.ltcha_lo);
FPrintf(fout, " Run mode: %s\n", cd.cra & 8 ? "One-shot" : "Continuous");
FPrintf(fout, " Input : %s\n", cd.cra & 0x20 ? "CNT" : "ø2");
FPuts(fout, " Output : ");
if (cd.cra & 2)
if (cd.cra & 4)
FPuts(fout, "PB6 Toggle\n\n");
else
FPuts(fout, "PB6 Pulse\n\n");
else
FPuts(fout, "None\n\n");
FPrintf(fout, "Timer B : %s\n", cd.crb & 1 ? "On" : "Off");
FPrintf(fout, " Counter : %04lx Latch: %04lx\n", (cd.tb_hi << 8) | cd.tb_lo, (cd.ltchb_hi << 8) | cd.ltchb_lo);
FPrintf(fout, " Run mode: %s\n", cd.crb & 8 ? "One-shot" : "Continuous");
FPuts(fout, " Input : ");
if (cd.crb & 0x40)
if (cd.crb & 0x20)
FPuts(fout, "Timer A underflow (CNT high)\n");
else
FPuts(fout, "Timer A underflow\n");
else
if (cd.crb & 0x20)
FPuts(fout, "CNT\n");
else
FPuts(fout, "ø2\n");
FPuts(fout, " Output : ");
if (cd.crb & 2)
if (cd.crb & 4)
FPuts(fout, "PB7 Toggle\n\n");
else
FPuts(fout, "PB7 Pulse\n\n");
else
FPuts(fout, "None\n\n");
FPrintf(fout, "TOD : %lx%lx:%lx%lx:%lx%lx.%lx %s\n",
(cd.tod_hr >> 4) & 1, cd.tod_hr & 0x0f,
(cd.tod_min >> 4) & 7, cd.tod_min & 0x0f,
(cd.tod_sec >> 4) & 7, cd.tod_sec & 0x0f,
cd.tod_10ths & 0x0f, cd.tod_hr & 0x80 ? "PM" : "AM");
FPrintf(fout, "Alarm : %lx%lx:%lx%lx:%lx%lx.%lx %s\n",
(cd.alm_hr >> 4) & 1, cd.alm_hr & 0x0f,
(cd.alm_min >> 4) & 7, cd.alm_min & 0x0f,
(cd.alm_sec >> 4) & 7, cd.alm_sec & 0x0f,
cd.alm_10ths & 0x0f, cd.alm_hr & 0x80 ? "PM" : "AM");
FPrintf(fout, "TOD input : %s\n", cd.cra & 0x80 ? "50Hz" : "60Hz");
FPrintf(fout, "Write to : %s registers\n\n", cd.crb & 0x80 ? "Alarm" : "TOD");
FPrintf(fout, "Serial data : %02lx\n", cd.sdr);
FPrintf(fout, "Serial mode : %s\n\n", cd.cra & 0x40 ? "Output" : "Input");
FPuts(fout, "Pending int.: ");
dump_cia_ints(cd.int_data);
FPuts(fout, "Enabled int.: ");
dump_cia_ints(cd.int_mask);
}
void dump_cia_ints(UBYTE int)
{
if (int & 0x1f) {
if (int & 1) FPuts(fout, "TA ");
if (int & 2) FPuts(fout, "TB ");
if (int & 4) FPuts(fout, "Alarm ");
if (int & 8) FPuts(fout, "Serial ");
if (int & 0x10) FPuts(fout, "Flag");
} else
FPuts(fout, "None");
FPutC(fout, '\n');
}
void view_sid_state(void)
{
SIDDump sd;
GetSIDDump(&sd);
FPuts(fout, "Voice 1\n");
FPrintf(fout, " Frequency : %04lx\n", (sd.freq_hi_1 << 8) | sd.freq_lo_1);
FPrintf(fout, " Pulse Width: %04lx\n", ((sd.pw_hi_1 & 0x0f) << 8) | sd.pw_lo_1);
FPrintf(fout, " Env. (ADSR): %lx %lx %lx %lx\n", sd.AD_1 >> 4, sd.AD_1 & 0x0f, sd.SR_1 >> 4, sd.SR_1 & 0x0f);
FPuts(fout, " Waveform : ");
dump_sid_waveform(sd.ctrl_1);
FPrintf(fout, " Gate : %s Ring mod.: %s\n", sd.ctrl_1 & 0x01 ? "On " : "Off", sd.ctrl_1 & 0x04 ? "On" : "Off");
FPrintf(fout, " Test bit : %s Synchron.: %s\n", sd.ctrl_1 & 0x08 ? "On " : "Off", sd.ctrl_1 & 0x02 ? "On" : "Off");
FPrintf(fout, " Filter : %s\n", sd.res_filt & 0x01 ? "On" : "Off");
FPuts(fout, "\nVoice 2\n");
FPrintf(fout, " Frequency : %04lx\n", (sd.freq_hi_2 << 8) | sd.freq_lo_2);
FPrintf(fout, " Pulse Width: %04lx\n", ((sd.pw_hi_2 & 0x0f) << 8) | sd.pw_lo_2);
FPrintf(fout, " Env. (ADSR): %lx %lx %lx %lx\n", sd.AD_2 >> 4, sd.AD_2 & 0x0f, sd.SR_2 >> 4, sd.SR_2 & 0x0f);
FPuts(fout, " Waveform : ");
dump_sid_waveform(sd.ctrl_2);
FPrintf(fout, " Gate : %s Ring mod.: %s\n", sd.ctrl_2 & 0x01 ? "On " : "Off", sd.ctrl_2 & 0x04 ? "On" : "Off");
FPrintf(fout, " Test bit : %s Synchron.: %s\n", sd.ctrl_2 & 0x08 ? "On " : "Off", sd.ctrl_2 & 0x02 ? "On" : "Off");
FPrintf(fout, " Filter : %s\n", sd.res_filt & 0x02 ? "On" : "Off");
FPuts(fout, "\nVoice 3\n");
FPrintf(fout, " Frequency : %04lx\n", (sd.freq_hi_3 << 8) | sd.freq_lo_3);
FPrintf(fout, " Pulse Width: %04lx\n", ((sd.pw_hi_3 & 0x0f) << 8) | sd.pw_lo_3);
FPrintf(fout, " Env. (ADSR): %lx %lx %lx %lx\n", sd.AD_3 >> 4, sd.AD_3 & 0x0f, sd.SR_3 >> 4, sd.SR_3 & 0x0f);
FPuts(fout, " Waveform : ");
dump_sid_waveform(sd.ctrl_3);
FPrintf(fout, " Gate : %s Ring mod.: %s\n", sd.ctrl_3 & 0x01 ? "On " : "Off", sd.ctrl_3 & 0x04 ? "On" : "Off");
FPrintf(fout, " Test bit : %s Synchron.: %s\n", sd.ctrl_3 & 0x08 ? "On " : "Off", sd.ctrl_3 & 0x02 ? "On" : "Off");
FPrintf(fout, " Filter : %s Mute : %s\n", sd.res_filt & 0x04 ? "On" : "Off", sd.mode_vol & 0x80 ? "Yes" : "No");
FPuts(fout, "\nFilters/Volume\n");
FPrintf(fout, " Frequency: %04lx\n", (sd.fc_hi << 3) | (sd.fc_lo & 0x07));
FPrintf(fout, " Resonance: %lx\n", sd.res_filt >> 4);
FPuts(fout, " Mode : ");
if (sd.mode_vol & 0x70) {
if (sd.mode_vol & 0x10) FPuts(fout, "Low-pass ");
if (sd.mode_vol & 0x20) FPuts(fout, "Band-pass ");
if (sd.mode_vol & 0x40) FPuts(fout, "High-pass");
} else
FPuts(fout, "None");
FPrintf(fout, "\n Volume : %lx\n", sd.mode_vol & 0x0f);
}
void dump_sid_waveform(UBYTE wave)
{
if (wave & 0xf0) {
if (wave & 0x10) FPuts(fout, "Triangle ");
if (wave & 0x20) FPuts(fout, "Sawtooth ");
if (wave & 0x40) FPuts(fout, "Rectangle ");
if (wave & 0x80) FPuts(fout, "Noise");
} else
FPuts(fout, "None");
FPutC(fout, '\n');
}
void view_vic_state(void)
{
VICDump vd;
short i;
GetVICDump(&vd);
FPrintf(fout, "Raster line : %04lx\n", vd.raster | ((vd.ctrl1 & 0x80) << 1));
FPrintf(fout, "IRQ raster line : %04lx\n\n", vd.irq_raster);
FPrintf(fout, "X scroll : %ld\n", vd.ctrl2 & 7);
FPrintf(fout, "Y scroll : %ld\n", vd.ctrl1 & 7);
FPrintf(fout, "Horizontal border : %ld columns\n", vd.ctrl2 & 8 ? 40 : 38);
FPrintf(fout, "Vertical border : %ld rows\n\n", vd.ctrl1 & 8 ? 25 : 24);
FPuts(fout, "Display mode : ");
switch (((vd.ctrl1 >> 5) & 3) | ((vd.ctrl2 >> 2) & 4)) {
case 0:
FPuts(fout, "Standard text\n");
break;
case 1:
FPuts(fout, "Multicolor text\n");
break;
case 2:
FPuts(fout, "Standard bitmap\n");
break;
case 3:
FPuts(fout, "Multicolor bitmap\n");
break;
case 4:
FPuts(fout, "ECM text\n");
break;
case 5:
FPuts(fout, "Invalid text (ECM+MCM)\n");
break;
case 6:
FPuts(fout, "Invalid bitmap (ECM+BMM)\n");
break;
case 7:
FPuts(fout, "Invalid bitmap (ECM+BMM+ECM)\n");
break;
}
FPrintf(fout, "Sequencer state : %s\n", vd.idle_state ? "Idle" : "Display");
FPrintf(fout, "Bad line state : %s\n", vd.bad_line ? "Yes" : "No");
FPrintf(fout, "Bad lines enabled : %s\n", vd.bad_line_enable ? "Yes" : "No");
FPrintf(fout, "Video counter : %04lx\n", vd.vc);
FPrintf(fout, "Video counter base: %04lx\n", vd.vcbase);
FPrintf(fout, "Row counter : %ld\n\n", vd.rc);
FPrintf(fout, "VIC bank : %04lx-%04lx\n", vd.bank_base, vd.bank_base + 0x3fff);
FPrintf(fout, "Video matrix base : %04lx\n", vd.matrix_base);
FPrintf(fout, "Character base : %04lx\n", vd.char_base);
FPrintf(fout, "Bitmap base : %04lx\n\n", vd.bitmap_base);
FPrintf(fout, " Spr.0 Spr.1 Spr.2 Spr.3 Spr.4 Spr.5 Spr.6 Spr.7\n");
FPuts(fout, "Enabled: "); dump_spr_flags(vd.me);
FPrintf(fout, "Data : %04lx %04lx %04lx %04lx %04lx %04lx %04lx %04lx\n",
vd.sprite_base[0], vd.sprite_base[1], vd.sprite_base[2], vd.sprite_base[3],
vd.sprite_base[4], vd.sprite_base[5], vd.sprite_base[6], vd.sprite_base[7]);
FPrintf(fout, "MC : %02lx %02lx %02lx %02lx %02lx %02lx %02lx %02lx\n",
vd.mc[0], vd.mc[1], vd.mc[2], vd.mc[3], vd.mc[4], vd.mc[5], vd.mc[6], vd.mc[7]);
FPuts(fout, "Mode : ");
for (i=0; i<8; i++)
if (vd.mmc & (1<<i))
FPuts(fout, "Multi ");
else
FPuts(fout, "Std. ");
FPuts(fout, "\nX-Exp. : "); dump_spr_flags(vd.mxe);
FPuts(fout, "Y-Exp. : "); dump_spr_flags(vd.mye);
FPuts(fout, "Prio. : ");
for (i=0; i<8; i++)
if (vd.mdp & (1<<i))
FPuts(fout, "Back ");
else
FPuts(fout, "Fore ");
FPuts(fout, "\n\nPending interrupts: ");
dump_vic_ints(vd.irq_flag);
FPuts(fout, "Enabled interrupts: ");
dump_vic_ints(vd.irq_mask);
}
void dump_spr_flags(UBYTE f)
{
short i;
for (i=0; i<8; i++)
if (f & (1<<i))
FPuts(fout, "Yes ");
else
FPuts(fout, "No ");
FPutC(fout, '\n');
}
void dump_vic_ints(UBYTE int)
{
if (int & 0x1f) {
if (int & 1) FPuts(fout, "Raster ");
if (int & 2) FPuts(fout, "Spr-Data ");
if (int & 4) FPuts(fout, "Spr-Spr ");
if (int & 8) FPuts(fout, "Lightpen");
} else
FPuts(fout, "None");
FPutC(fout, '\n');
}
/*
* Daten laden
* l start "file"
*/
void load_data(void)
{
UWORD adr;
BPTR file;
LONG fc;
if (!expression(&adr))
return;
if (the_token == T_END) {
error("Missing file name");
return;
}
if (the_token != T_STRING) {
error("'\"' around file name expected");
return;
}
if (!(file = Open(the_string, MODE_OLDFILE)))
error("Unable to open file");
else {
while ((fc = FGetC(file)) >= 0)
SAMWriteByte(adr++, fc);
Close(file);
}
}
/*
* Daten speichern
* s start end "file"
*/
void save_data(void)
{
BOOL done = FALSE;
UWORD adr, end_adr;
BPTR file;
if (!expression(&adr))
return;
if (!expression(&end_adr))
return;
if (the_token == T_END) {
error("Missing file name");
return;
}
if (the_token != T_STRING) {
error("'\"' around file name expected");
return;
}
if (!(file = Open(the_string, MODE_NEWFILE)))
error("Unable to create file");
else {
do {
if (adr == end_adr) done = TRUE;
FPutC(file, SAMReadByte(adr++));
} while (!done);
Close(file);
}
}